/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.structure.resource.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.biz.modular.structure.resource.entity.BizModule;
import vip.xiaonuo.biz.modular.structure.resource.enums.BizResourceCategoryEnum;
import vip.xiaonuo.biz.modular.structure.resource.param.module.BizModuleIdParam;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.listener.CommonDataChangeEventCenter;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.core.enums.BizBuildInEnum;
import vip.xiaonuo.biz.core.enums.BizDataTypeEnum;
import vip.xiaonuo.biz.modular.structure.relation.entity.BizRelation;
import vip.xiaonuo.biz.modular.structure.relation.enums.BizRelationCategoryEnum;
import vip.xiaonuo.biz.modular.structure.relation.service.BizRelationService;
import vip.xiaonuo.biz.modular.structure.resource.entity.BizMenu;
import vip.xiaonuo.biz.modular.structure.resource.entity.BizModule;
import vip.xiaonuo.biz.modular.structure.resource.enums.BizResourceCategoryEnum;
import vip.xiaonuo.biz.modular.structure.resource.mapper.BizModuleMapper;
import vip.xiaonuo.biz.modular.structure.resource.param.module.BizModuleAddParam;
import vip.xiaonuo.biz.modular.structure.resource.param.module.BizModuleEditParam;
import vip.xiaonuo.biz.modular.structure.resource.param.module.BizModuleIdParam;
import vip.xiaonuo.biz.modular.structure.resource.param.module.BizModulePageParam;
import vip.xiaonuo.biz.modular.structure.resource.service.BizMenuService;
import vip.xiaonuo.biz.modular.structure.resource.service.BizModuleService;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 模块Service接口实现类
 *
 * @author xuyuxiang
 * @date 2022/6/27 14:25
 **/
@Service
public class BizModuleServiceImpl extends ServiceImpl<BizModuleMapper, BizModule> implements BizModuleService {

    @Resource
    private BizMenuService bizMenuService;

    @Resource
    private BizRelationService bizRelationService;

    @Override
    public Page<BizModule> page(BizModulePageParam bizModulePageParam) {
        QueryWrapper<BizModule> queryWrapper = new QueryWrapper<BizModule>().checkSqlInjection();
        queryWrapper.lambda().eq(BizModule::getCategory, BizResourceCategoryEnum.MODULE.getValue());
        if(ObjectUtil.isNotEmpty(bizModulePageParam.getSearchKey())) {
            queryWrapper.lambda().like(BizModule::getTitle, bizModulePageParam.getSearchKey());
        }
        if(ObjectUtil.isAllNotEmpty(bizModulePageParam.getSortField(), bizModulePageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(bizModulePageParam.getSortOrder());
            queryWrapper.orderBy(true, bizModulePageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(bizModulePageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(BizModule::getSortCode);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(BizModuleAddParam bizModuleAddParam) {
        BizModule bizModule = BeanUtil.toBean(bizModuleAddParam, BizModule.class);
        boolean repeatTitle = this.count(new LambdaQueryWrapper<BizModule>().eq(BizModule::getCategory,
                BizResourceCategoryEnum.MODULE.getValue()).eq(BizModule::getTitle, bizModule.getTitle())) > 0;
        if(repeatTitle) {
            throw new CommonException("存在重复的模块，名称为：{}", bizModule.getTitle());
        }
        bizModule.setCode(RandomUtil.randomString(10));
        bizModule.setCategory(BizResourceCategoryEnum.MODULE.getValue());
        this.save(bizModule);

        // 发布增加事件
        CommonDataChangeEventCenter.doUpdateWithData(BizDataTypeEnum.RESOURCE.getValue(), JSONUtil.createArray().put(bizModule));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BizModuleEditParam bizModuleEditParam) {
        BizModule bizModule = this.queryEntity(bizModuleEditParam.getId());
        BeanUtil.copyProperties(bizModuleEditParam, bizModule);
        boolean repeatTitle = this.count(new LambdaQueryWrapper<BizModule>().eq(BizModule::getCategory,
                BizResourceCategoryEnum.MODULE.getValue()).eq(BizModule::getTitle, bizModule.getTitle())
                .ne(BizModule::getId, bizModule.getId())) > 0;
        if(repeatTitle) {
            throw new CommonException("存在重复的模块，名称为：{}", bizModule.getTitle());
        }
        this.updateById(bizModule);

        // 发布更新事件
        CommonDataChangeEventCenter.doUpdateWithData(BizDataTypeEnum.RESOURCE.getValue(), JSONUtil.createArray().put(bizModule));
    }

    @Override
    public void delete(List<BizModuleIdParam> bizModuleIdParamList) {
        List<String> bizModuleIdList = CollStreamUtil.toList(bizModuleIdParamList, BizModuleIdParam::getId);
        if(ObjectUtil.isNotEmpty(bizModuleIdList)) {
            boolean containsBiztemModule = this.listByIds(bizModuleIdList).stream().map(BizModule::getCode)
                    .collect(Collectors.toSet()).contains(BizBuildInEnum.BUILD_IN_MODULE_CODE.getValue());
            if(containsBiztemModule) {
                throw new CommonException("不可删除系统内置模块");
            }

            // 获取模块下的菜单、按钮
            List<BizMenu> allMenuList = bizMenuService.list(new LambdaQueryWrapper<BizMenu>()
                    .in(BizMenu::getCategory, CollectionUtil.newArrayList(BizResourceCategoryEnum.MENU.getValue(),
                            BizResourceCategoryEnum.BUTTON.getValue())));
            if(ObjectUtil.isNotEmpty(allMenuList)) {
                List<String> toDeleteMenuIdList = CollectionUtil.newArrayList(bizModuleIdList);
                allMenuList.stream().filter(bizMenu -> bizModuleIdList.contains(bizMenu.getModule()))
                        .collect(Collectors.toList()).forEach(bizMenu -> toDeleteMenuIdList
                        .addAll(bizMenuService.getChildListById(allMenuList, bizMenu.getId(), true).stream()
                                .map(BizMenu::getId).collect(Collectors.toList())));
                if(ObjectUtil.isNotEmpty(toDeleteMenuIdList)) {
                    // 清除对应的角色与资源信息
                    bizRelationService.remove(new LambdaUpdateWrapper<BizRelation>().in(BizRelation::getTargetId, toDeleteMenuIdList)
                            .eq(BizRelation::getCategory, BizRelationCategoryEnum.SYS_ROLE_HAS_RESOURCE.getValue()));
                    // 执行删除
                    this.removeByIds(toDeleteMenuIdList);

                    // 发布删除事件
                    CommonDataChangeEventCenter.doDeleteWithDataId(BizDataTypeEnum.RESOURCE.getValue(), toDeleteMenuIdList);
                }
            }
        }
    }

    @Override
    public List<JSONObject> moduleSelector() {
        LambdaQueryWrapper<BizModule> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.select(BizModule::getId, BizModule::getTitle);
        lambdaQueryWrapper.eq(BizModule::getCategory, BizResourceCategoryEnum.MODULE.getValue());
        return this.list(lambdaQueryWrapper).stream()
                .map(item -> JSONUtil.createObj().set("id", item.getId()).set("name", item.getTitle()))
                .collect(Collectors.toList());
    }

    @Override
    public BizModule detail(BizModuleIdParam bizModuleIdParam) {
        return this.queryEntity(bizModuleIdParam.getId());
    }

    @Override
    public BizModule queryEntity(String id) {
        BizModule bizModule = this.getById(id);
        if(ObjectUtil.isEmpty(bizModule)) {
            throw new CommonException("模块不存在，id值为：{}", id);
        }
        return bizModule;
    }
}
